#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include "wrap.h"

#define MAXLINE 80
#define SERV_PORT 8000

int main(int argc, char **argv)
{
    int i, max_i, max_fd, listen_fd, conn_fd, sock_fd;
    int nready, client[FD_SETSIZE];
    ssize_t n;
    fd_set rset, allset;
    char buf[MAXLINE];
    char str[INET_ADDRSTRLEN];
    socklen_t cli_addr_len;
    struct sockaddr_in cli_addr, serv_addr;

    listen_fd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&serv_addr, sizeof(struct sockaddr_in));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(SERV_PORT);

    Bind(listen_fd, (struct sockaddr *)&serv_addr, \
            sizeof(struct sockaddr_in));

    Listen(listen_fd, 20);

    max_fd = listen_fd;
    max_i = 3;

    memset(client, -1, FD_SETSIZE);
    FD_ZERO(&allset);
    FD_SET(listen_fd, &allset);

    for (;;) {
        rset = allset; /* structure assignment. */
        nready = select(max_fd+1, &rset, NULL, NULL, NULL);
        if (nready < 0)
            perr_exit("select error");

        if (FD_ISSET(listen_fd, &rset)) {
            printf("%s:%d\n", __FUNCTION__, __LINE__);
            /* new client connection. */
            cli_addr_len = sizeof(cli_addr);
            conn_fd = Accept(listen_fd, (struct sockaddr *)&cli_addr, \
                    &cli_addr_len);
            printf("received from %s at PORT:%d\n", \
                    (char *)inet_ntop(AF_INET, &cli_addr.sin_addr, \
                        str, sizeof(str)), \
                    ntohs(cli_addr.sin_port));

            for (i = 0; i < FD_SETSIZE; i++)
                if (client[i] < 0) {
                    client[i] = conn_fd; /* save descripter. */
                    break;
                }
            if (i == FD_SETSIZE) {
                fputs("too many clients.\n", stderr);
                exit(1);
            }

            FD_SET(conn_fd, &allset); /* add new descriptor to set. */
            if (conn_fd > max_fd)
                max_fd = conn_fd; /* for select. */
            if (i > max_fd)
                max_i = i; /* max index in client array. */

            if (--nready == 0)
                continue; /* no more readable descriptors. */
        }

        for (i = 0; i <= max_i; i++) {
            /* check all clients for data. */
            if ((sock_fd = client[i]) < 0)
                continue;
            if (FD_ISSET(sock_fd, &rset)) {
                if ((n = Read(sock_fd, buf, MAXLINE)) == 0) {
                    /* connection closed by client. */
                    Close(sock_fd);
                    FD_CLR(sock_fd, &allset);
                    client[i] = -1;
                } else {
                    int k;
                    for (k = 0; k < n; k++)
                        buf[k] = toupper(buf[k]);
                    Write(sock_fd, buf, n);
                }

                if (--nready == 0)
                    break; /* no more readable descriptors. */
            }
        }
    }
}

